package com.medusa.aps.business.modules.basic.model;

import cn.hutool.core.annotation.Alias;
import cn.hutool.core.util.ReflectUtil;
import com.alibaba.fastjson2.annotation.JSONField;
import com.medusa.aps.business.util.DateTimeUtils;
import com.medusa.aps.business.global.model.exception.GlobalException;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Null;
import jakarta.validation.constraints.Size;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.experimental.Accessors;

import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;

/**
 * 工作时段数据
 *
 * @author 张治保
 * @since 2023-10-07
 */
@Getter
@Setter
@ToString
@Accessors(chain = true)
@Schema(description = "工作时段数据")
public class WorkingPeriodModel {

    private static final int MAX_PERIOD_SIZE = 4;

    /**
     * 工作时段id
     */
    @Schema(description = "主键id", example = "1")
    private Integer id;

    /**
     * 工作时段名称
     */
    @Alias("工作时段名称")
    @Schema(description = "工作时段名称", example = "单班制")
    @NotBlank(message = "工作时段名称不能为空")
    @Size(min = 1, max = 50, message = "工作时段名称长度为1-50")
    private String name;

    /**
     * 是否不可编辑
     */
    @Schema(description = "是否不可编辑", accessMode = Schema.AccessMode.READ_ONLY)
    @Null
    private Boolean unEditable;

    /**
     * 工作时段列表
     * todo 前端不友好 应前端要求 故暂时舍弃该字段
     */
//    @NotNull(message = "工作时段列表不能为空")
//    @Size(min = 1, max = MAX_PERIOD_SIZE, message = "工作时段列表长度为1-4")
//    private List<WorkPeriod> periods;


    /**
     * 前端不友好 应前端要求 故调整为以下数据
     */
    @Alias("时段1开始时间")
    @NotNull(message = "时段1开始时间不能为空")
    @JSONField(format = DateTimeUtils.HOUR_MINUTE_PATTERN)
    @Schema(description = "时段1开始时间", type = "string", example = "09:00")
    private LocalTime start1;

    @Alias("时段1结束时间")
    @NotNull(message = "时段1结束时间不能为空")
    @JSONField(format = DateTimeUtils.HOUR_MINUTE_PATTERN)
    @Schema(description = "时段1结束时间", type = "string", example = "18:00")
    private LocalTime end1;

    @Alias("时段2开始时间")
    @JSONField(format = DateTimeUtils.HOUR_MINUTE_PATTERN)
    @Schema(description = "时段2开始时间", type = "string", example = "09:00")
    private LocalTime start2;

    @Alias("时段2结束时间")
    @JSONField(format = DateTimeUtils.HOUR_MINUTE_PATTERN)
    @Schema(description = "时段2结束时间", type = "string", example = "18:00")
    private LocalTime end2;

    @Alias("时段3开始时间")
    @JSONField(format = DateTimeUtils.HOUR_MINUTE_PATTERN)
    @Schema(description = "时段3开始时间", type = "string", example = "09:00")
    private LocalTime start3;

    @Alias("时段3结束时间")
    @JSONField(format = DateTimeUtils.HOUR_MINUTE_PATTERN)
    @Schema(description = "时段3结束时间", type = "string", example = "18:00")
    private LocalTime end3;

    @Alias("时段4开始时间")
    @JSONField(format = DateTimeUtils.HOUR_MINUTE_PATTERN)
    @Schema(description = "时段4开始时间", type = "string", example = "09:00")
    private LocalTime start4;

    @Alias("时段4结束时间")
    @JSONField(format = DateTimeUtils.HOUR_MINUTE_PATTERN)
    @Schema(description = "时段4结束时间", type = "string", example = "18:00")
    private LocalTime end4;


    /**
     * 工作时段列表展开 用于前端展示
     *
     * @param periods 工作时段列表
     * @return 工作时段列表
     */
    public WorkingPeriodModel periods(List<WorkPeriod> periods) {
        int size = periods.size();
        if (size > MAX_PERIOD_SIZE) {
            throw new GlobalException("工作时段列表长度不能超过4");
        }
        for (int index = 0; index < size; index++) {
            WorkPeriod workPeriod = periods.get(index);
            int currentIndex = index + 1;
            ReflectUtil.invoke(this, "setStart" + currentIndex, workPeriod.getStart());
            ReflectUtil.invoke(this, "setEnd" + currentIndex, workPeriod.getEnd());
        }
        return this;
    }

    /**
     * 工作时段列表收缩
     *
     * @return 工作时段列表
     */
    @JSONField(serialize = false)
    public List<WorkPeriod> periods() {
        List<WorkPeriod> periods = new ArrayList<>(MAX_PERIOD_SIZE);
        periods.add(new WorkPeriod().setStart(start1).setEnd(end1));
        if ((start2 == null && end2 != null) || (start2 != null && end2 == null)) {
            throw new GlobalException("工作时段2开始时间和结束时间必须同时存在");
        }
        if (start2 != null) {
            periods.add(new WorkPeriod().setStart(start2).setEnd(end2));
        }
        if ((start3 == null && end3 != null) || (start3 != null && end3 == null)) {
            throw new GlobalException("工作时段3开始时间和结束时间必须同时存在");
        }
        if (start3 != null) {
            periods.add(new WorkPeriod().setStart(start3).setEnd(end3));
        }
        if ((start4 == null && end4 != null) || (start4 != null && end4 == null)) {
            throw new GlobalException("工作时段4开始时间和结束时间必须同时存在");
        }
        if (start4 != null) {
            periods.add(new WorkPeriod().setStart(start4).setEnd(end4));
        }
        return periods;
    }

    /**
     * 校验所有工作时段 并且检查是否有交集
     */
    public void valid() {
        List<WorkPeriod> periods = periods();
        for (int i = 0; i < periods.size(); i++) {
            WorkPeriod period = periods.get(i);
            period.valid();
            for (int j = i + 1; j < periods.size(); j++) {
                WorkPeriod other = periods.get(j);
                if (period.isOverlap(other)) {
                    throw new GlobalException("工作时段不能有交集");
                }
            }
        }
    }

}
